/*
 * SWELatexEditor Undo Redo functionality
 */

package com.meraklisina.latexeditor;

import com.meraklisina.latexeditor.mdi.TextEditor.TextEditors;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JTabbedPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

/**
 * Undo Redo Functionaly. <br /> 
 * This class adds undo / redo to JTextPane which is added in JTabbedPanel
 *
 * @author Suleyman Melikoglu
 */
public class UndoRedo {

    private JTextPane TabbedTextPane;
    private JMenuItem jMenuItemUndo;
    private JMenuItem jMenuItemRedo;
    final UndoManager undo;

    /**
     * Constructor method.<br />
     * Adds the undo redo actions to given textPane. <br />
     * Also adds event listeners,<br />
     * Binds the actions to the certain keystrokes
     *
     * @param textPane
     */
    public UndoRedo(JTextPane textPane, JMenuItem menuItemUndo, JMenuItem menuItemRedo){
        this.TabbedTextPane = textPane;
        this.undo = new UndoManager();
        this.jMenuItemUndo = menuItemUndo;
        this.jMenuItemRedo = menuItemRedo;

        // apply undo / redo stuff to given textPane
        this._undoStuff();
    }

    /**
     * Constructor method.<br />
     * Instantiates an empty UndoRedo class
     */
    public UndoRedo(){
        this.undo = new UndoManager();
    }

    private void  _undoStuff(){

        Document doc = this.TabbedTextPane.getDocument();

        // Listen for undo and redo events
        doc.addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent evt) {
                undo.addEdit(evt.getEdit());
            }
        });

        // Create an undo action and add it to the text component
        this.TabbedTextPane.getActionMap().put("Undo",
            new AbstractAction("Undo") {
                public void actionPerformed(ActionEvent evt) {
                    _undo();
                }
        });

        // Bind the undo action to ctl-Z
        this.TabbedTextPane.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");

        // Add undo action to the menu item
        this.jMenuItemUndo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                _undo();
            }
        });

        // Create a redo action and add it to the text component
        this.TabbedTextPane.getActionMap().put("Redo",
            new AbstractAction("Redo") {
                public void actionPerformed(ActionEvent evt) {
                    _redo();
                }
            });

        // Bind the redo action to ctl-Y
        this.TabbedTextPane.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");

        // Add redo action to the menu item
        this.jMenuItemRedo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                _redo();
            }
        });
    }

    private void _undo(){
        try {
            if (undo.canUndo()) {
                undo.undo();
            }
        } catch (CannotUndoException e) {
        }
    }

    private void _redo(){
        try {
            if (undo.canRedo()) {
                undo.redo();
            }
        } catch (CannotRedoException e) {
        }
    }

    /**
     * Apply undo/redo functionality to existing JTextPanes. <br />
     * This method is useful for adding this functionaly when textPanes are
     * loaded from the latest session
     *
     * @param tab_Editors
     */
    public void applyToTextEditors(JTabbedPane tab_Editors, JMenuItem menuItemUndo, JMenuItem menuItemRedo){
        TextEditors ClsTextEditor = new TextEditors();
        int size = ClsTextEditor.getEditors().size();
        for( ; ( size - 1 ) >= 0; size-- ){
             new UndoRedo((ClsTextEditor.GetJTextPaneAt(tab_Editors, size - 1)), menuItemUndo, menuItemRedo);
        }
    }
}
